/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: xio.h
 *
 * Purpose: xio base API define
 *
 * Developer:
 *   wen.gu , 2023-07-07
 *
 * TODO:
 *
 ***************************************************************************/

#ifndef __XBUS_TRANSPORT_XIO_H__
#define __XBUS_TRANSPORT_XIO_H__

#include <string>
#include <memory>
#include <functional>

#include "xbus/core/xtype.h"
#include "xbus/core/xerror.h"
#include "xbus/transport/message_receiver.h"
#include "xbus/transport/message_sender.h"

namespace xbus::transport {


class XIO {
public:
    using XErrC = core::XErrC;
    using XComId = core::XComId;
    using XMessagePtr = core::XMessagePtr;
    using WorkerHandler = std::function<void(core::XComId com_id, XMessageQueuePtr mq_ptr)>;
public:
    XIO(const std::string& io_name, int32_t send_priority, int32_t recv_priority)
    :io_name_(io_name),
    sender_(io_name + "_send", send_priority),
    receiver_(io_name + "_recv", recv_priority){ /**todo something */ }
    virtual ~XIO() { stop(); }
public:
    virtual void set_recv_queue(XMessageQueuePtr mq_ptr) { receiver_.set_msg_queue(mq_ptr); }
    virtual void set_send_queue(XMessageQueuePtr mq_ptr) { sender_.set_msg_queue(mq_ptr); }
    virtual XMessageQueuePtr recv_queue() const { return receiver_.msg_queue(); }
    virtual XMessageQueuePtr send_queue() const { return sender_.msg_queue(); }

    /**if max size == 0, then indicat unlimited the size of message queue */
    virtual XErrC alloc_recv_queue(uint32_t max_size = 0) { return receiver_.alloc_msg_queue(max_size); }
    virtual XErrC alloc_send_queue(uint32_t max_size = 0) { return sender_.alloc_msg_queue(max_size); }


    /** only for the io which has send/recv thread/worker */
    virtual int32_t send_priority() { return sender_.priority(); }
    virtual int32_t recv_priority() { return receiver_.priority(); }
    virtual void set_com_id(core::XComId com_id) { 
        sender_.set_com_id(com_id);
        receiver_.set_com_id(com_id);
     }
    virtual core::XComId com_id() { return sender_.com_id(); }
    
    virtual void set_send_handler(WorkerHandler&& handler) { sender_.set_worker_handler(std::forward<WorkerHandler>(handler)); }
    virtual void set_recv_handler(WorkerHandler&& handler) { receiver_.set_worker_handler(std::forward<WorkerHandler>(handler));}

    virtual const std::string& name() { return io_name_; }
public:
    virtual XErrC start() {// start sender and receiver to working
        auto ret = sender_.start();
        if (XErrC::OK == ret) {
            return receiver_.start();
        }

        return ret;
    }
    virtual XErrC stop() {  //stop will call clear() also 
        auto ret = receiver_.stop();

        if (XErrC::OK == ret) {
            return sender_.stop();
        }
        return ret;
    }

    virtual XErrC clear() { // clear(drop) all data cached message in worker (include sender and receiver).
        auto ret = receiver_.clear();

        if (XErrC::OK == ret) {
            return sender_.clear();
        }
        return ret;        
    }

    virtual XErrC flush(int32_t timeout_ms = core::WaitType::WaitForever) { //wait for all message in sender to be sent.
        return sender_.flush(timeout_ms);
    }

public:
    virtual XErrC send(XMessagePtr msg_ptr) { return sender_.send(msg_ptr); }
    virtual XErrC send(uint8_t type, const uint8_t* payload_data, uint32_t payload_size) { return sender_.send(type, payload_data, payload_size); }

    /** this API will alloc message with 'payload_size' and call 'fill_handler' method to fill payload to message */
    virtual XErrC send(uint8_t type, uint32_t payload_size, MessageSender::DataFillHandler& fill_handler) { return sender_.send(type, payload_size, fill_handler); }

public: /** receiver API */
    /** timeout_ms: see also 'class Timeout',
     * NoWait: if haven't message received, then return immediately
     * WaitForever: if haven't message received, then recv() will be block until receive a message or the XEndpoint is stopped
     * > 0: if haven't message received, then recv() will be block until receive a message or the XEndpoint is stopped or timeout
    */
    virtual core::XResult<XMessagePtr> recv(int32_t timeout_ms = core::WaitType::WaitForever) { return receiver_.recv(timeout_ms); }
protected:
    std::string io_name_;
    MessageSender sender_;
    MessageReceiver receiver_;
};



} //namespace xbus::transport


#endif /** !__XBUS_TRANSPORT_XIO_H__ */